
package de.justphil.tcg.tcgserver.game.mechanics.game;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import de.justphil.tcg.tcgserver.game.mechanics.config.Config;
import de.justphil.tcg.tcgserver.game.mechanics.monster.Monster;
import de.justphil.tcg.tcgserver.game.mechanics.monster.MonsterList;
import org.slf4j.Logger;
import static de.justphil.tcg.tcgserver.commons.logging.TCGLogging.*;

public class GameBoard implements BoardInfo, GameDataSerializable {
	
	private static final Logger	log	= gameLogger(GameBoard.class);
	private final Monster[][]	board;
	
	public GameBoard() {
	
		board = new Monster[Config.NUM_PLAYERS][Config.NUM_SLOTS_PER_PLAYER];
	}
	
	@Override
	public boolean isEmpty(BoardPosition position) {
	
		return board[position.getPlayer()][position.getSlot()] == null;
	}
	
	@Override
	public Monster getMonster(BoardPosition position) {
	
		return board[position.getPlayer()][position.getSlot()];
	}
	
	@Override
	public int getOwner(Monster monster) {
	
		if (monster == null) {
			log.warn("Trying to get the BoardPosition of a Null-Monster!", new Object[] {});
			return -1;
		}
		int owner = -1;
		for (int player = 0; player < Config.NUM_PLAYERS; player++) {
			for (int slot = 0; slot < Config.NUM_SLOTS_PER_PLAYER; slot++) {
				if (board[player][slot] != null && board[player][slot].equals(monster)) {
					owner = player;
					break;
				}
			}
			if (owner != -1) {
				break;
			}
		}
		return owner;
	}
	
	@Override
	public MonsterList getAll() {
	
		MonsterList monsters = new MonsterList();
		for (int player = 0; player < Config.NUM_PLAYERS; player++) {
			for (int slot = 0; slot < Config.NUM_SLOTS_PER_PLAYER; slot++) {
				if (this.board[player][slot] != null) {
					monsters.add(this.board[player][slot]);
				}
			}
		}
		return monsters;
	}
	
	@Override
	public MonsterList getAllies(Monster monster) {
	
		return getMonsters(getOwner(monster));
	}
	
	@Override
	public MonsterList getMonsters(int owner) {
	
		MonsterList monsters = new MonsterList();
		if (owner < 0 || owner >= Config.NUM_PLAYERS) {
			log.warn("Trying to get the monsters from an invalid owner {}!", new Object[] {
				owner });
			assert false;
			return monsters;
		}
		for (int slot = 0; slot < Config.NUM_SLOTS_PER_PLAYER; slot++) {
			if (this.board[owner][slot] != null) {
				monsters.add(this.board[owner][slot]);
			}
		}
		return monsters;
	}
	
	/**
	 * Only working for two players!
	 * 
	 * @param monster
	 * @return
	 */
	@Override
	public MonsterList getEnemies(Monster monster) {
	
		int owner = getOwner(monster);
		int enemyPlayer = (owner + 1) % 2;
		return getMonsters(enemyPlayer);
	}
	
	@Override
	public BoardPosition getBoardPosition(Monster monster) {
	
		for (int player = 0; player < Config.NUM_PLAYERS; player++) {
			for (int slot = 0; slot < Config.NUM_SLOTS_PER_PLAYER; slot++) {
				if (board[player][slot] != null && board[player][slot].equals(monster)) {
					return new BoardPosition(player, slot);
				}
			}
		}
		return null;
	}
	
	public void setSlot(Monster monster, BoardPosition position) {
	
		if (getAll().contains(monster)) {
			log.error(
					"Trying to set a Monster ({}) to position ({}) although it is already on the Board!",
					new Object[] {
							monster, position });
		}
		assert !(getAll().contains(monster)) : "Trying to set a monster which is already on the board!";
		// if (getAll().contains(monster)) {
		//
		// Log.println(
		// "Trying to set a monster which is already on the board!",
		// Log.ERROR);
		// return;
		// }
		board[position.getPlayer()][position.getSlot()] = monster;
	}
	
	public void clearSlot(BoardPosition position) {
	
		board[position.getPlayer()][position.getSlot()] = null;
	}
	
	@Override
	public void writeData(Game game, DataOutput out) throws IOException {
	
		for (int player = 0; player < board.length; player++) {
			for (int slot = 0; slot < board[player].length; slot++) {
				game.getDataSerializableManager().writeMonster(board[player][slot], game, out);
			}
		}
	}
	
	@Override
	public void readData(Game game, DataInput in) throws IOException {
	
		for (int player = 0; player < board.length; player++) {
			for (int slot = 0; slot < board[player].length; slot++) {
				board[player][slot] = game.getDataSerializableManager().readMonster(game, in);
			}
		}
	}
}
